package piis;

import Algorithms.BackPropagation;
import MainProgram.Plot;
import NeuronNetworkLibrary.Network;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import utilities.PiisWriter;
import utilities.Utilities;

public class Test11 {

    static String path = "src/test1";
    public final static int EPOCH = 1000;
    public final static double ERROR = 10e-30;

    public static void main(String[] args) {

        File dir = new File(path);
        String[] files = dir.list();

        if (files == null) {
            System.out.println("Empty directory");
        } else {
            for (int x = 0; x < files.length; x++) {
                if (files[x].endsWith(".in") && files[x].startsWith("mlp_bp_ts_")) {
                    prepareAndInvoke(files[x]);
                    Network.INIT_WEIGHTS_FLAG = true;
                }
            }
        }
    }

    public static void prepareAndInvoke(String name) {

        try {
            Scanner sc = new Scanner(new File(path + "/" + name));

            int h = sc.nextInt();
            double min = Double.valueOf(sc.next());
            double max = Double.valueOf(sc.next());
            ArrayList<Double> x = new ArrayList<>();
            ArrayList<Double> y = new ArrayList<>();
            while (sc.hasNext()) {
                x.add(Double.valueOf(sc.next()));
                y.add(Double.valueOf(sc.next()));
            }

            backPropagationPerceptron(h, x.toArray(new Double[x.size()]), y.toArray(new Double[y.size()]), name, min, max);
            sc.close();

        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public static void backPropagationPerceptron(int h, Double[] x, Double[] y, String name, double min, double max) {

        double obtainedResults[][];

        double[][] trainingSet = new double[x.length][1];
        double[][] desiredOutput = new double[y.length][1];
        ArrayList<Double> errors = new ArrayList<>();

        for (int i = 0; i < x.length; i++) {
            trainingSet[i][0] = x[i];
        }
        for (int i = 0; i < y.length; i++) {
            desiredOutput[i][0] = y[i];
        }


        Network network = new Network(trainingSet, desiredOutput, new int[]{h}, new String[]{"sigmo"}, "linear");
        
        int i = 0;
        int order[];
        do {
            // Randomize which trainingSet will be trained.
            order = MainProgram.Main.randomizeOrder(network.getNumberOfPatterns());
            for (int j = 0; j < network.getNumberOfPatterns(); j++) {

                // Calculate forwardly the network outputs.
                network.calculateNetwork(order[j]);

                // Use Backpropagation algorithm to change the weights. 
                BackPropagation.calculateBackPropagation(network);
            }
            errors.add(network.getMSE());
            i++;
        } while (i <= EPOCH && network.getMSE() > ERROR);

        //Save errors
        PiisWriter.write(
                Utilities.convertToStringArrayList(errors), 
                path + "/"+ name.replace(".in", "_train.out")
                );

        // Second part: calculating values from interval: <-5, 5> 
        double[][] newTrainingSet = Utilities.generateTrainingSet(min, max, 0.1);
        double[][] newDesiredOutput = new double[newTrainingSet.length][1];

        network.setDesiredOutputs(newDesiredOutput);
        network.setTrainingSet(newTrainingSet);
        network.updateNumberOfPatterns();
        
        obtainedResults = new double[newTrainingSet.length][1];
        
        ArrayList<String> output = new ArrayList<>();
        for (int j = 0; j < network.getNumberOfPatterns(); j++) {
            
            network.calculateNetwork(j);
            obtainedResults[j][0] = network.getOutputLayer().get(0).getCalculatedOutput();
            
            String s = String.valueOf(network.getTrainingSet()[j][0]);
            s += " " + String.valueOf(obtainedResults[j][0]);
            output.add(s);
        }
        
        // Save the results
        PiisWriter.write(output, path + "/" + name.replace(".in", "_result.out"));

        // Show plot
        Plot plot = new Plot(
                name, //window title 
                name, //plot title
                trainingSet, //training set 
                desiredOutput, //desired output
                network.getTrainingSet(),
                obtainedResults //obtained result
                );
        plot.setVisible(true);
        
        System.out.println("Test with file: " + name + " has been finished.");
    }
}
